Dans ce notebook, nous allons essayer de faire du text mining pour récuper des versions locales des programmes des présidentielles 2017 des candidats suivants :
Différentes manières de récupérer les programmes sont possibles : soit à partir des fichiers .pdf, soit à partir des sites des campagnes. Nous allons faire au plus simple, à l'aide des sites de campagnes.
In [1]:
from bs4 import BeautifulSoup
import requests
import re
import pandas as pd
from ipywidgets import interact
In [2]:
def make_df_from_props_sources(props_sources):
"Makes a big dataframe from props_sources."
dfs = []
for key in props_sources:
df = pd.DataFrame(props_sources[key], columns=['proposition'])
df['source'] = key
dfs.append(df)
df = pd.concat(dfs).reset_index(drop=True)
return df
Le projet de François Fillon ne sera annoncé que le 13 mars : https://www.fillon2017.fr/projet/
In [129]:
r = requests.get('https://www.fillon2017.fr/projet/')
soup = BeautifulSoup(r.text, 'html.parser')
In [130]:
tags = soup.find_all('a', class_='projectItem__inner')
In [131]:
sublinks = [tag.attrs['href'] for tag in tags]
In [132]:
r = requests.get('https://www.fillon2017.fr/projet/competitivite/')
soup = BeautifulSoup(r.text, 'html.parser')
In [133]:
tags = soup.find_all('li', class_='singleProject__propositionItem')
In [134]:
len(tags)
Out[134]:
In [135]:
tag = tags[0]
In [136]:
tag.find('div', class_='singleProject__propositionItem-content').text
Out[136]:
In [137]:
for tag in tags:
tag.find('div', class_='singleProject__propositionItem-content').text
In [138]:
def extract_propositions(url):
r = requests.get(url)
soup = BeautifulSoup(r.text, 'html.parser')
tags = soup.find_all('li', class_='singleProject__propositionItem')
return [tag.find('div', class_='singleProject__propositionItem-content').text for tag in tags]
In [139]:
extract_propositions(sublinks[0])
Out[139]:
In [140]:
props_sources = {}
for sublink in sublinks:
props = extract_propositions(sublink)
props_sources[sublink] = props
In [141]:
df = make_df_from_props_sources(props_sources)
df.head()
Out[141]:
In [142]:
df.to_csv('../projets/francois_fillon.csv', index=False, quoting=1)
Les 144 engagements de Marine Le Pen peuvent être consultés ici : https://www.marine2017.fr/programme/
Apparemment, les différentes propositions sont imbriquées dans des balises <p>
.
<p>3. <strong>Permettre la représentation de tous les Français</strong> par le scrutin proportionnel à toutes les élections. À l’Assemblée nationale, la proportionnelle sera intégrale avec une prime majoritaire de 30 % des sièges pour la liste arrivée en tête et un seuil de 5 % des suffrages pour obtenir des élus.</p>
On peut donc extraire ces éléments et les trier ensuite.
Téléchargeons le code source de la page.
In [16]:
r = requests.get('https://www.marine2017.fr/programme/')
In [17]:
soup = BeautifulSoup(r.text, "html.parser")
Maintenant, chercons à extraire tous les paragraphes, à l'aide d'une fonction qui vérifie que le paragraphe commence par un nombre suivi d'un point (et peut-être d'un espace).
In [18]:
pattern = re.compile('^\d+.\s*')
In [19]:
def filter_func(tag):
if tag.text is not None:
return pattern.match(tag.text) is not None
else:
return False
In [20]:
all_paragraphs = [re.split(pattern, tag.text)[1:] for tag in soup.find_all('p') if filter_func(tag)]
In [21]:
len(all_paragraphs)
Out[21]:
In [22]:
@interact
def disp_para(n=(0, len(all_paragraphs) - 1)):
print(all_paragraphs[n])
In [23]:
props_sources = {}
props_sources['https://www.marine2017.fr/programme/'] = all_paragraphs
In [24]:
df = make_df_from_props_sources(props_sources)
In [25]:
df.head(10)
Out[25]:
Bien, on peut maintenant écrire ces données dans un fichier texte.
In [26]:
df.to_csv('../projets/marine_le_pen.csv', index=False, quoting=1)
Le site de Benoît Hamon ne permet pas d'accéder à une page avec toutes les propositions facilement. Du coup, il faut explorer trois sous-catégories.
In [27]:
r = requests.get('https://www.benoithamon2017.fr/thematique/pour-un-progres-social-et-ecologique/')
r
Out[27]:
In [28]:
soup = BeautifulSoup(r.text, 'html.parser')
In [29]:
all_propositions = soup.find_all(class_='Propositions-Proposition')
In [30]:
len(all_propositions)
Out[30]:
In [31]:
p = all_propositions[0]
In [32]:
p.text
Out[32]:
In [33]:
p.find('h1').text
Out[33]:
In [34]:
p.find('p').text
Out[34]:
On peut extraire de ces propositions la moëlle essentielle :
In [35]:
def extract_data(tag):
"Extracts title for tag and content."
subject = tag.find('h1').text
content = tag.find('p').text
return subject, content
Construisons une table de données avec ces propositions.
In [36]:
df = pd.DataFrame([extract_data(p) for p in all_propositions], columns=['titre', 'contenu'])
In [37]:
df
Out[37]:
In [38]:
df[df['contenu'].str.contains('ascension')]
Out[38]:
On peut transformer ces propositions en DataFrame.
In [39]:
props_sources = {}
props_sources['https://www.benoithamon2017.fr/thematique/pour-un-progres-social-et-ecologique/'] = df['contenu'].values.tolist()
In [40]:
df = make_df_from_props_sources(props_sources)
In [41]:
df.head()
Out[41]:
In [42]:
df.to_csv('../projets/benoit_hamon.csv', index=False, quoting=1)
On peut trouver une version inofficielle du programme ici : https://laec.fr/sommaire
Un peu comme pour le site d'Hamon, il y a des rubriques. Commençons par la première.
In [43]:
r = requests.get('https://laec.fr/chapitre/1/la-6e-republique')
In [44]:
soup = BeautifulSoup(r.text, 'html.parser')
In [45]:
sublinks = soup.find_all('a', class_='list-group-item')
In [46]:
sublinks
Out[46]:
On peut étendre cette manière de récupérer les données à toutes les sous-sections :
In [47]:
suburls = ['https://laec.fr/chapitre/1/la-6e-republique',
'https://laec.fr/chapitre/2/proteger-et-partager',
'https://laec.fr/chapitre/3/la-planification-ecologique',
'https://laec.fr/chapitre/4/sortir-des-traites-europeens',
'https://laec.fr/chapitre/5/pour-l-independance-de-la-france',
'https://laec.fr/chapitre/6/le-progres-humain-d-abord',
'https://laec.fr/chapitre/7/la-france-aux-frontieres-de-l-humanite']
In [48]:
sublinks = []
for suburl in suburls:
r = requests.get(suburl)
soup = BeautifulSoup(r.text, 'html.parser')
sublinks.extend(soup.find_all('a', class_='list-group-item'))
In [49]:
sublinks[:5]
Out[49]:
Combien de propositions trouvons-nous ?
In [50]:
len(sublinks)
Out[50]:
Construisons les url complètes.
In [51]:
full_urls = ['https://laec.fr' + link.attrs['href'] for link in sublinks]
full_urls[:10]
Out[51]:
In [52]:
full_url = full_urls[13]
#full_url = full_urls[0]
In [53]:
r = requests.get(full_url)
In [54]:
print(r.text[:800])
In [55]:
soup = BeautifulSoup(r.text, 'html.parser')
In [56]:
tags = soup.find_all('li', class_='list-group-item')
In [57]:
tag = tags[0]
In [58]:
tag.text
Out[58]:
In [59]:
tag.find_all('li')
Out[59]:
In [60]:
tag.p.text
Out[60]:
In [61]:
"\n".join([t.text for t in tag.find_all('li')])
Out[61]:
In [62]:
len(tags)
Out[62]:
In [63]:
[tag.text for tag in tags]
Out[63]:
In [64]:
def extract_data(url):
r = requests.get(url)
soup = BeautifulSoup(r.text, 'html.parser')
tags = soup.find_all('li', class_='list-group-item')
contents = []
for tag in tags:
if len(tag.find_all('li')) == 0:
contents.append(tag.text)
else:
contents.append(tag.p.text + '\n\t' + "\n\t".join([t.text for t in tag.find_all('li')]))
return contents
In [65]:
extract_data(full_url)
Out[65]:
In [66]:
extract_data(full_urls[13])
Out[66]:
In [67]:
props_sources = {}
for url in full_urls:
props_sources[url] = extract_data(url)
In [68]:
df = make_df_from_props_sources(props_sources)
df
Out[68]:
On écrit un fichier.
In [69]:
df.to_csv('../projets/jean_luc_melenchon.csv', index=False, quoting=1)
Il faut dans un premier temps aller chercher les pages individuelles du site.
In [70]:
r = requests.get('https://en-marche.fr/emmanuel-macron/le-programme')
soup = BeautifulSoup(r.text, 'html.parser')
In [71]:
proposals = soup.find_all(class_='programme__proposal')
proposals = [p for p in proposals if 'programme__proposal--category' not in p.attrs['class']]
In [72]:
len(proposals)
Out[72]:
In [73]:
full_urls = ["https://en-marche.fr" + p.find('a').attrs['href'] for p in proposals]
In [74]:
url = full_urls[1]
In [75]:
r = requests.get(url)
In [76]:
text = r.text
In [77]:
text = text.replace('</br>', '')
In [78]:
soup = BeautifulSoup(text, 'html.parser')
In [79]:
article_tag = soup.find_all('article', class_='l__wrapper--slim')[0]
In [80]:
for line in article_tag.find_all(class_='arrows'):
print(line.text)
In [81]:
tag = article_tag.find_all(class_='arrows')[-1]
In [82]:
tag.text
Out[82]:
In [83]:
tag.next_sibling
Out[83]:
In [84]:
def extract_items(url):
r = requests.get(url)
text = r.text.replace('</br>', '')
soup = BeautifulSoup(text, 'html.parser')
article_tag = soup.find_all('article', class_='l__wrapper--slim')[0]
return [line.text.strip() for line in article_tag.find_all(class_='arrows')]
In [85]:
extract_items(full_urls[1])
Out[85]:
On extrait toutes les propositions.
In [86]:
propositions = [extract_items(url) for url in full_urls]
In [87]:
len(propositions)
Out[87]:
In [88]:
full_urls[18]
Out[88]:
In [89]:
@interact
def print_prop(n=(0, len(propositions) - 1)):
print(propositions[n])
In [90]:
props_sources = {}
for url, props in zip(full_urls, propositions):
props_sources[url] = props
In [91]:
df = make_df_from_props_sources(props_sources)
In [92]:
df.head()
Out[92]:
In [93]:
df.iloc[0, 1]
Out[93]:
In [94]:
df.to_csv('../projets/emmanuel_macron.csv', index=False, quoting=1)
In [95]:
r = requests.get('http://avecjadot.fr/lafrancevive/')
In [96]:
soup = BeautifulSoup(r.text, 'html.parser')
In [97]:
tags = soup.find_all('div', class_='bloc-mesure')
In [98]:
links = [tag.find('a').attrs['href'] for tag in tags]
In [99]:
all([link.startswith('http://avecjadot.fr/') for link in links])
Out[99]:
Extraction du titre d'une des pages.
In [100]:
link = links[0]
In [101]:
r = requests.get(link)
In [102]:
soup = BeautifulSoup(r.text, 'html.parser')
In [103]:
soup.find('div', class_='texte-mesure').text.strip().replace('\n', ' ')
Out[103]:
In [104]:
def extract_data(link):
r = requests.get(link)
soup = BeautifulSoup(r.text, 'html.parser')
return soup.find('div', class_='texte-mesure').text.strip().replace('\n', ' ')
In [105]:
extract_data(link)
Out[105]:
In [106]:
all_props = [extract_data(link) for link in links]
In [107]:
props_sources = {}
for url, props in zip(links, all_props):
props_sources[url] = [props]
In [108]:
props_sources
Out[108]:
In [109]:
df = make_df_from_props_sources(props_sources)
In [110]:
df.head()
Out[110]:
In [111]:
df.to_csv('../projets/yannick_jadot.csv', index=False, quoting=1)
In [112]:
r = requests.get('http://www.nda-2017.fr/themes.html')
soup = BeautifulSoup(r.text, 'html.parser')
In [113]:
len(soup.find_all('div', class_='theme'))
Out[113]:
In [114]:
links = ['http://www.nda-2017.fr' + tag.find('a').attrs['href'] for tag in soup.find_all('div', class_='theme')]
In [115]:
link = links[0]
In [116]:
r = requests.get(link)
In [117]:
soup = BeautifulSoup(r.text, 'html.parser')
In [118]:
tags = soup.find_all('div', class_='proposition')
In [119]:
len(tags)
Out[119]:
In [120]:
tags[0].find('a').text.strip()
Out[120]:
In [121]:
tags[0].find('a').attrs['href']
Out[121]:
In [122]:
def extract_data(link):
r = requests.get(link)
soup = BeautifulSoup(r.text, 'html.parser')
tags = soup.find_all('div', class_='proposition')
return [tag.find('a').text.strip() for tag in tags]
In [123]:
all_props = [extract_data(link) for link in links]
In [124]:
len(all_props)
Out[124]:
In [125]:
props_sources = {}
for url, props in zip(links, all_props):
props_sources[url] = props
In [126]:
df = make_df_from_props_sources(props_sources)
In [127]:
df
Out[127]:
In [128]:
df.to_csv('../projets/nicolas_dupont_aignan.csv', index=False, quoting=1)